package com.crack.smartgit.allkill.transformer;

import com.crack.smartgit.VersionMap;
import jdk.internal.org.objectweb.asm.Type;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.List;

/**
 * 目标：通杀
 * @author Administrator
 * @descript
 * @date 2019-08-25
 */
public class SmartGitTransformer implements ClassFileTransformer {

    public SmartGitTransformer(){

    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        if(className != null && !"".equals(className.trim())){
            try{
                ClassReader classReader = new ClassReader(classfileBuffer);
                ClassNode classNode = new ClassNode();
                classReader.accept(classNode,0);
                List<MethodNode> methodNodes = classNode.methods;
                boolean haveField = false;
                if(classNode.name.contains(VersionMap.ALL_KILL.get(VersionMap.ENTRY))){
                    System.out.println(classNode.name);
                    for (final MethodNode methodNode : methodNodes) {
                        Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
                        Type returnType = Type.getReturnType(methodNode.desc);
                        if (Type.VOID_TYPE != returnType) {
                            continue;
                        }
                        if(argumentTypes.length != 2 || !methodNode.desc.contains(VersionMap.ALL_KILL.get(VersionMap.PARMTYPELIST))){
                            continue;
                        }
                        boolean haveMessageDigest = false;
                        boolean haveMath = false;
                        InsnList insnList = methodNode.instructions;
                        for (int i = 0;i<insnList.size();i++){
                            if(insnList.get(i).getOpcode() == Opcodes.BIPUSH){
                                IntInsnNode intInsnNode = (IntInsnNode)insnList.get(i);
                                if(intInsnNode.operand == 16){
                                    haveMessageDigest = true;
                                }
                            }
                            if(haveMessageDigest){
                                if(insnList.get(i).getOpcode() == Opcodes.INVOKESTATIC){
                                    System.out.println("");
                                    MethodInsnNode methodInsnNode = (MethodInsnNode)insnList.get(i);
                                    if(methodInsnNode.owner.contains(VersionMap.ALL_KILL.get(VersionMap.METHOD)) && methodInsnNode.name.equals("min")){
                                        haveMath = true;
                                        insnList.set(insnList.get(0),new InsnNode(Opcodes.RETURN));
                                        methodNode.exceptions.clear();
                                        methodNode.visitEnd();
                                        break;
                                    }
                                }
                            }
                        }
                        if(haveMath){
                            ClassWriter cw = new ClassWriter(0);
                            classNode.accept(cw);
                            byte[] classCode = cw.toByteArray();
                            if(Boolean.valueOf(VersionMap.ALL_KILL.get(VersionMap.IS_DEBUG))){
                                try {
                                    FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\Administrator\\Desktop\\"+classNode.name.replaceAll("/","_")+".class"));
                                    fos.write(classCode, 0, classCode.length);
                                    fos.close();
                                }catch (Exception e){

                                }
                            }
                            return classCode;
                        }
                    }
                }
            }catch (Exception e){

            }
        }
        return classfileBuffer;
    }
}
